/** Index types*/
export = {};

/** 参看03interface/04可索引类型Indexable Types*/

function pluck<T,K extends keyof T>(o:T,names:K[]):T[K][] {
  //T => {name:string,age:number,grade:number}
  /** keyof是ts里的关键字,它能取得它操作对象的所有key的名字,并以字符串字面量的形式组成联合类型*/
  //keyof T => 'name'|'age'|'grade'   // keyof得到的一定是一个联合字符串字面量类型
  //K extends keyof T => 'name'|'age'|'grade'   // 这里的extends和js的继承没有关系 是类型之间的继承
  //K[] = ('name'|'age'|'grade')[]    // 这就能让ts帮我们检查第二个参数names接受的实参中的键名是不是都存在于第一个参数o所接受的实参中


  //T[K]什么意思？
  //T => {name:string,age:number,grade:number}
  //K => 'name'|'age'|'grade'
  //T[K] => 如果你传的是name 则T[K]为string; 如果你传的是age 则T[K]为number; 如果你传的是grade 则T[K]为number;


  //那么T[K][]是什么东东呢？
  //正向理解我们不好理解 我们反过来推
  return names.map(n => o[n]);
  // 我们的返回值是['ahhh',18,100]
  // 它用的类型应该这样描述:
  // Array<string|number>
  // 或则 (string|number)[] (而不是(string|number|number)[],因为联合类型会自动将相同的类型去掉,So想要达到你想的那种效果应该使用元组类型去限制)
  // 那么这个string是怎么取到的呢?
  // 假定我们的T的类型此时为Person
  // Array<Person[name]|Person[age]|Person[grade]>
  // Array<T[name]|T[age]|T[grade]>
  // Array<T[k1]|T[k2]|T[k3]> // ←相同类型会在联合类型中被去重
  // Array<T[K]>
  // ↑可改写成↓
  // T[K][]
}

pluck({name: 'ahhh', age: 18, grade: 100}, ['name', 'age', 'xxx']);



type a = 'a'|'a'|'a' // type a1 = "a"
type a1 = 'a'|'b'|'b' // type a1 = "a" | "b"
// let a2: ('a'|'b')[] = ['a', 'b', 'a', 'b'];
let a2: a1[] = ['a', 'b', 'a', 'b'];
